<!doctype html>

<html>

<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />

  <title>Basis Demos: Basis.js blog</title>

  <link rel="stylesheet" type="text/css" title="Default Style" href="../../style/style.css" media="screen" />

  <style type="text/css">
    HTML,
    BODY
    {
      background: #F0F0F0;
      heigh4t: 100%;
    }
    BODY
    {
      padding: 20px 0;
    }

    A
    {
      color: #06D;
    }

    #page
    {
      min-width: 600px;
      max-width: 1000px;
      margin: 0px auto 0;
      background: white;
    }
    #page-wrapper
    {
      border: 1px solid #E0E0E0;
      margin: 0 -1px;
      overflow: hidden;
    }
    #sidebar
    {
      float: right;
      height: 100%;
      width: 25%;
      min-width: 180px;
      padding: 10px;
      margin-left: 10px
    }
    #content
    {
      overflow: hidden;
      padding: 10px;
    }
    #footer
    {
      height: 2em;
    }

    .Basis-Paginator
    {
      float: right;
    }
    .Basis-Paginator .Basis-PaginatorNode
    {
      width: 4ex;
    }

    #blog-thread
    {
      clear: both;
    }
    .blog-post
    {
      margin: 1.5em 0 2em;
    }
    .blog-post__title
    {
      margin: 0;
      font-size: 160%;
      color: #2A80EE;
      font-weight: normal; 
      font-family: 'Segoe UI', Arial;
      text-decoration: underline;
      cursor: pointer;
      display: inline;
    }
    .blog-post__title:hover
    {
      color: red;
    }
    .blog-post__pubDate
    {
      font-size: 80%;
      color: #666;
      display: block;
      margin: .5em 0;
    }
    .blog-post__content
    {
      margin: .75em 0;
      color: #333;
      text-transform: capitalize;
    }
    .blog-post__footer
    {
      font-size: 90%;
      border-top: 1px solid #F8F8F8;
      padding-top: .2em;
    }
    .blog-post__category
    {
      min-width: 24ex;
      padding-right: 2ex;
      white-space: nowrap;
      float: left;
    }
    .blog-post__category-link
    {
      color: #2A80EE;
      cursor: pointer;
      text-decoration: underline;
    }
    .blog-post__category-link:hover
    {
      color: red;
    }
    .blog-post__tag-list .tag__title
    {
      text-decoration: underline;
      color: #2A80EE;
      cursor: pointer;
    }
    .blog-post__tag-list .tag__title:hover
    {
      color: red;
    }
    .blog-post__tag-list .tag
    {
      padding-right: .6em;
    }
    .blog-post__tag-list .tag:not(:last-child):after
    {
      content: ',';
    }

    .category-list__header,
    .archive-list__header,
    .tag-cloud__header
    {
      font-size: 140%;
      background: #2A80EE;
      color: white;
      margin: 0 -0px;
      padding: .2em 10px .3em;
      font-weight: normal;
      font-family: 'Segoe UI', Arial;
    }
    .category-list__content
    {
      margin: 0;
      padding: 1em 1ex 1em 2ex;
    }
    .category-list-item
    {
      list-style: none;
      margin: 0;
      padding: 0;
      color: blue;
      text-decoration: underline;
      cursor: pointer;
    }
    .category-list-item:hover
    {
      color: red;
    }

    .archive-list__content
    {
      padding: 1em 0 1em 16px;
      margin: 0;
    }
    .archive-list-group
    {
      list-style: none;
    }
    .archive-list-group__title
    {
      margin-left: -16px;
      padding: .2em 0 .2em 16px;
      cursor: pointer;
      background: url(arrow_down.png) no-repeat 6px center;
    }
    .archive-list-group__title:hover
    {
      background-color: #F0F0F0;
    }
    .archive-list-group__content
    {
      padding: 0 0 1em 2ex;
      margin: 0;
    }
    .archive-list-group_collapsed .archive-list-group__title
    {
      background-image: url(arrow_right.png);
      background-position: 8px center;
    }
    .archive-list-group_collapsed .archive-list-group__content
    {
      display: none;
    }
    .archive-list-item__link
    {
      color: blue;
      text-decoration: underline;
      cursor: pointer;
    }
    .archive-list-item
    {
      list-style: none;
      margin: 0;
      padding: 0;
    }
    .archive-list-item__link:hover
    {
      color: red;
    }

    .tag-cloud__content
    {
      text-align: center;
      padding: 1em 0;
    }
    .cloud-tag
    {
      margin-right: 8px;
      cursor: pointer;
      -webkit-transition: font-size .5s;
    }
    .cloud-tag:hover
    {
      color: red;
    }


  </style>

  <script>var firstTime = new Date;</script>
  <script src="../../basis-all.js"></script>
  <script src="../seedrandom.js"></script>
  <script>Math.seedrandom("basis");</script>
  <script src="blog_posts-5000.js"></script>
  <script>

    basis.dom.event.onLoad(runApp = function(){
      var statOutElement = basis.dom.createElement('ul');

      function outStat(){
        var sdate = times.shift();

        var timelist = statOutElement;
        var lasttime = sdate;
        for (var i = 0; i < times.length; i++)
        {
          var t = times[i];
          timelist.appendChild(basis.dom.createElement('LI', (t[0] - sdate) + 'ms, self: ' + (t[0] - (lasttime)) + ' [' + t[1] + ']'));
          lasttime = t[0];
        }
        timelist.appendChild(basis.dom.createElement('B', lasttime - sdate));
        timelist.appendChild(basis.dom.createElement('SPAN', ' (' + (lasttime - firstTime) + ')'));
      }

      var times = [new Date];

      //console.profile();

      var DataObject = basis.data.DataObject;
      var allPostDataset = new basis.data.Dataset({
        items: window.rawData.map(function(data){
          data.tags = data.tags.split(/\s*,\s*/);

          if (data.tags[0] == '')
            data.tags.shift();

          return new DataObject({
            data: data
          });
        })
      });

      //console.profileEnd();
      times.push([new Date, 'data load']);

      //console.profile();

      var POST_PER_PAGE = 15;

      var blogThreadPage = new basis.data.dataset.Slice({
        source: allPostDataset,
        orderDesc: true,
        limit: POST_PER_PAGE,
        rule: 'data.pubDate'
      });

      times.push([new Date, 'thread slice']);

      var paginator = new basis.ui.paginator.Paginator({
        pageCount: Math.ceil(allPostDataset.itemCount / POST_PER_PAGE),
        pageSpan: 12,
        handler: {
          activePageChanged: function(){
            blogThreadPage.setRange(this.activePage * POST_PER_PAGE, POST_PER_PAGE);
          }
        }
      });

      blogThreadPage.addHandler({
        sourceChanged: function(ds){
          this.setProperties(ds.source ? Math.ceil(ds.source.itemCount / POST_PER_PAGE) : 0, 10, 0);
          this.spotlightPage(0);
        }
      }, paginator);

      var postList = new basis.ui.Container({
        dataSource: blogThreadPage,
        sorting: 'data.pubDate',
        sortingDesc: true,
        id: 'blog-thread',
        childClass: {
          template: 
            '<div class="blog-post">' +
              '<h2 class="blog-post__title">{title}</h2>' +
              '<span class="blog-post__pubDate">[#{id}] {pubDate}</span>' +
              '<div{content} class="blog-post__content"/>' +
              '<div class="blog-post__footer">' +
                '<span class="blog-post__category">' +
                  'Category: ' +
                  '<span class="blog-post__category-link" event-click="filterByCategory">{category}</span>' +
                '</span>' +
                '<!--{tagList}-->' +
              '</div>' +
            '</div>',

          binding: {
            id: 'data:',
            title: 'data:',
            category: 'data:',
            pubDate: {
              events: 'update',
              getter: function(node){
                return Date.fromISOString(node.data.pubDate).toFormat('%D/%M/%Y %H:%I:%S');
              }
            },
            tagList: 'satellite:'
          },

          templateUpdate: function(tmpl, eventName, delta){
            /*tmpl.id.nodeValue = this.data.id;
            tmpl.title.nodeValue = this.data.title;
            tmpl.pubDate.nodeValue = Date.fromISOString(this.data.pubDate).toFormat('%D/%M/%Y %H:%I:%S');*/
            tmpl.content.innerHTML = this.data.content;
            //tmpl.category.nodeValue = this.data.category;
          },

          action: {
            filterByCategory: function(){
              blogThreadPage.setSource(postByCategory.getSubset(this.data.category));
            }
          },

          satelliteConfig: {
            tagList: {
              existsIf: function(owner){
                return owner.data.tags && owner.data.tags.length;
              },
              delegate: Function.$self,
              instanceOf: basis.ui.Container.subclass({
                template:
                  '<div class="blog-post__tag-list">' +
                    'Tags: <!--{childNodesHere}-->' +
                  '</div>',

                templateUpdate: function(object, eventName, delta){
                  this.setChildNodes(this.data.tags.map(function(tag){
                    return {
                      data: { title: tag }
                    };
                  }));
                },

                childClass: {
                  template:
                    '<span class="tag">' +
                      '<span class="tag__title" event-click="pick">{title}</span>' +
                    '</span>',

                  binding: {
                    title: 'data:title'
                  },

                  action: {
                    pick: function(){
                      blogThreadPage.setSource(cloud.getSubset(this.data.title));
                    }
                  }
                }
              })
            }
          }
        }
      });


      times.push([new Date, 'post list']);


      var postByCategory = new basis.data.dataset.Split({
        source: allPostDataset,
        rule: 'data.category'
      });

      var categoryList = new basis.ui.Container({
        dataSource: postByCategory,
        template:
          '<div class="category-list">' +
            '<h2 class="category-list__header">Category</h2>' +
            '<ul{childNodesElement} class="category-list__content"/>' +
          '</div>',

        childClass: {
          template:
            '<li class="category-list-item" event-click="choose">{title}</li>',

          binding: {
            title: 'data:title'
          },

          action: {
            choose: function(){
              blogThreadPage.setSource(this.delegate);
            }
          }
        }
      });


      times.push([new Date, 'category list']);


      var MONTH = 'January February March April May June July August September October November December'.qw();
      archiveList = new basis.ui.Container({
        dataSource: new basis.data.dataset.Split({
          source: allPostDataset,
          rule: 'data.pubDate.substr(0, 7)'
        }),
        sorting: 'data.id',
        sortingDesc: true,
        grouping: {
          groupGetter: 'data.id.substr(0, 4)',
          sorting: 'data.id',
          sortingDesc: true,
          childClass: {
            template:
              '<li class="archive-list-group">' +
                '<div class="archive-list-group__title" event-click="toggle">{title}</div>' +
                '<ul{childNodesElement} class="archive-list-group__content"/>' +
              '</li>',

            action: {
              toggle: function(){
                basis.cssom.classList(this.element).toggle('archive-list-group_collapsed');
              }
            }
          }
        },
        template:
          '<div class="archive-list">' +
            '<h2 class="archive-list__header">Archive</h2>' +
            '<ul{childNodesElement} class="archive-list__content"/>' +
          '</div>',

        childClass: {
          template:
            '<li class="archive-list-item">' +
              '<span class="archive-list-item__link" event-click="choose">{title}</span> ({count})' +
            '</li>',

          binding: {
            count: 'delegate.itemCount',
            title: function(node){
              return MONTH[node.data.id.substr(5) - 1];
            }
          },

          action: {
            choose: function(){
              blogThreadPage.setSource(this.delegate);
            }
          },

          listen: {
            delegate: {
              datasetChanged: function(){
                this.tmpl.set('count', this.delegate.itemCount);
              }
            }
          }
        }
      });

      times.push([new Date, 'archive list']);

      var cloud = new basis.data.dataset.Cloud({
        source: allPostDataset,
        rule: 'data.tags'
      });

      var cloudCalcs = new basis.data.index.IndexMap({
        source: cloud,
        indexes: {
          itemCountMin: basis.data.index.min('itemCount'),
          itemCountMax: basis.data.index.max('itemCount')
        },
        calcs: {
          percentOfMax: function(data, indexes, obj){
            return (obj.itemCount - indexes.itemCountMin) / (indexes.itemCountMax - indexes.itemCountMin);
          },
          source: function(data, indexes, obj){
            return obj;
          }
        },
        ruleEvents: {
          datasetChanged: true
        }
      });

      var tagCloud = new basis.ui.Container({
        id: 'tag-cloud',
        dataSource: cloudCalcs,
        sorting: 'data.title',
        template:
          '<div class="tag-cloud">' +
            '<h2 class="tag-cloud__header">Tags cloud</h2>' +
            '<div{childNodesElement} class="tag-cloud__content"/>' +
          '</div>',

        childClass: {
          active: true,

          template: 
            '<span class="cloud-tag" event-click="pick"> {title} </span>',

          binding: {
            title: 'data.source.data.title'
          },

          templateUpdate: function(tmpl){
            this.element.style.fontSize = '{0:.2}%'.format(80 + 120 * this.data.percentOfMax.fit(0, 1));
          },

          action: {
            pick: function(){
              blogThreadPage.setSource(this.data.source);
            }
          }
        }
      });

      times.push([new Date, 'tag cloud']);

      var app = new basis.ui.Node({
        container: document.body,

        template: 
          '<div id="page">' +
            '<div id="page-wrapper">' +
              '<div id="sidebar">' +
                '<!--{categoryList}-->' +
                '<!--{archiveList}-->' +
                '<!--{tagCloud}-->' +
              '</div>' +
              '<div{content} id="content">' +
                '<h1>Basis.js blog</h1>' +
                '<button event-click="reset">Show all posts</button>' +
                '<!--{paginator}-->' +
                '<!--{postList}-->' +
              '</div>' +
            '</div>' +
          '</div>',

        binding: {
          paginator: 'satellite:paginator',
          postList: 'satellite:postList',

          categoryList: 'satellite:categoryList',
          tagCloud: 'satellite:tagCloud',
          archiveList: 'satellite:archiveList'
        },

        action: {
          reset: function(){
            blogThreadPage.setSource(allPostDataset);
          }
        },

        satellite: {
          paginator: paginator,
          postList: postList,

          categoryList: categoryList,
          archiveList: archiveList,
          tagCloud: tagCloud
        }
      });

      basis.dom.insert(app.tmpl.content, statOutElement, 1);

      times.push([new Date, 'app']);

      outStat();

      //console.profileEnd();

//      basis.dom.get('asd').src= 'data:text/html;plain,' + JSON.stringify(postList);
    });
  </script>
</head>

<body>
  <div id="footer"></div>
</body>

</html>